﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition;

namespace FluentMef.Tests
{
    [TestClass]
    public class Composition_Tests
    {

        [TestMethod]
        public void Basic_For_Use()
        {
            var catalog = ContainerFactory.CreateContainer(x =>
            {
                x.For<ITest>().Use<TestA>();
            });

            var container = new CompositionContainer(catalog);

            var instance = container.GetExportedValue<ITest>();

            Assert.IsNotNull(instance);
            Assert.IsInstanceOfType(instance, typeof(TestA));
            Assert.IsTrue(instance.RunTest());
        }

        [TestMethod]
        public void Basic_For_Use_Func()
        {
            var catalog = ContainerFactory.CreateContainer(x =>
            {
                x.For<ITest>().Use(() => new TestA());
            });

            var container = new CompositionContainer(catalog);

            var instance = container.GetExportedValue<ITest>();

            Assert.IsNotNull(instance);
            Assert.IsInstanceOfType(instance, typeof(TestA));
            Assert.IsTrue(instance.RunTest());
        }

        [TestMethod]
        public void Basic_For_Use_Func_ContractName()
        {
            var catalog = ContainerFactory.CreateContainer(x =>
            {
                x.For<ITest>("test-contract").Use(() => new TestA());
            });

            var container = new CompositionContainer(catalog);

            var instance = container.GetExportedValue<ITest>("test-contract");

            Assert.IsNotNull(instance);
            Assert.IsInstanceOfType(instance, typeof(TestA));
            Assert.IsTrue(instance.RunTest());
        }

        [TestMethod]
        public void Basic_For_Use_Instance()
        {
            var expected = new TestA();

            var catalog = ContainerFactory.CreateContainer(x =>
            {
                x.For<ITest>().Use(expected);
            });

            var container = new CompositionContainer(catalog);

            var instance = container.GetExportedValue<ITest>();

            Assert.IsNotNull(instance);
            Assert.IsInstanceOfType(instance, typeof(TestA));
            Assert.AreSame(expected, instance);
            Assert.IsTrue(instance.RunTest());
        }

        [TestMethod]
        public void Basic_Constructor_Test()
        {
            var catalog = ContainerFactory.CreateContainer(x =>
                {
                    x.For<ITest>().Use<TestA>();
                    x.For<ConstructorTest>().Use<ConstructorTest>().ConstructWith<ITest>();
                });

            var container = new CompositionContainer(catalog);

            var instance = container.GetExportedValue<ConstructorTest>();

            Assert.IsNotNull(instance);
            Assert.IsTrue(instance.Tester.RunTest());
        }

        [TestMethod]
        public void Basic_ImportExplicit_Test()
        {
            var catalog = ContainerFactory.CreateContainer(x =>
            {
                x.For<ITest>().Use<TestA>();
                x.For<ImportExplicitTest>().Use<ImportExplicitTest>().Import(i => i.Tester);
            });

            var container = new CompositionContainer(catalog);

            var instance = container.GetExportedValue<ImportExplicitTest>();

            Assert.IsNotNull(instance);
            Assert.IsTrue(instance.Tester.RunTest());
        }
    }

    interface ITest
    {
        bool RunTest();
    }

    class TestA : ITest
    {
        public bool RunTest()
        {
            return true;
        }
    }

    sealed class ConstructorTest
    {
        public ITest Tester;

        public ConstructorTest(ITest tester)
        {
            if (tester == null) throw new ArgumentNullException("tester");

            Tester = tester;
        }
    }

    sealed class ImportExplicitTest
    {
        public ITest Tester { get; set; }
    }
}
